# gui_task.py
import sys
import os
import json
from pathlib import Path
from functools import partial

from PyQt5 import QtWidgets, QtCore, QtGui

# 假设 task.py 与 gui_task.py 在同一路径下
# task.py 中需包含：load_and_prepare_data, setup_selenium, navigate_and_login,
# manually_operated, fill_and_submit_forms, preprocess_captcha 等函数
# 如果 task.py 函数名不同，请调整 import
try:
    from task import (
        load_and_prepare_data,
        setup_selenium,
        navigate_and_login,
        manually_operated,
        fill_and_submit_forms,
        preprocess_captcha,
    )
except Exception as e:
    print("Failed to import from task.py:", e)
    # 仍继续运行 GUI，但会在运行时提示缺少模块/函数

CONFIG_FILE = Path.home() / ".my_task_gui_config.json"


class WorkerThread(QtCore.QThread):
    """用于在后台运行长任务（selenium 登录 + 提交）的线程"""

    log_signal = QtCore.pyqtSignal(str)
    finished_signal = QtCore.pyqtSignal(bool, str)

    def __init__(self, config):
        super().__init__()
        self.config = config
        self._is_running = True

    def run(self):
        try:
            self.log_signal.emit("开始读取 Excel ...")
            df = load_and_prepare_data(self.config["excel_path"])
            self.log_signal.emit(f"读取完成：{len(df)} 行")
        except Exception as e:
            self.finished_signal.emit(False, f"读取 Excel 出错: {e}")
            return

        # 启动浏览器
        try:
            self.log_signal.emit("启动浏览器...")
            driver = setup_selenium(self.config["driver_path"])
        except Exception as e:
            self.finished_signal.emit(False, f"启动浏览器失败: {e}")
            return

        try:
            self.log_signal.emit("尝试自动登录（包含验证码识别）...")
            flag = navigate_and_login(driver, self.config["site_url"], self.config["username"], self.config["password"])
            if not flag:
                self.log_signal.emit("自动登录未成功，切换到人工输入验证码模式（在浏览器中输入）...")
                manually_operated(driver, self.config["site_url"], self.config["username"], self.config["password"])
            self.log_signal.emit("登录成功，开始提交表单...")
            fill_and_submit_forms(driver, df)
            self.finished_signal.emit(True, "操作完成")
        except Exception as e:
            self.finished_signal.emit(False, f"运行中发生异常: {e}")
        finally:
            try:
                driver.quit()
                self.log_signal.emit("浏览器已关闭")
            except Exception:
                pass


class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("自动表单提交工具（GUI）")
        self.resize(820, 560)

        self.config = {
            "site_url": "http://lsfs.wzy-i.com/",
            "username": "",
            "password": "",
            "excel_path": "",
            "driver_path": "",
        }
        self.load_config()

        self._build_ui()
        self._apply_config_to_ui()
        self.worker = None

    def _build_ui(self):
        layout = QtWidgets.QVBoxLayout(self)

        form = QtWidgets.QFormLayout()
        self.site_edit = QtWidgets.QLineEdit()
        self.user_edit = QtWidgets.QLineEdit()
        self.pwd_edit = QtWidgets.QLineEdit()
        self.pwd_edit.setEchoMode(QtWidgets.QLineEdit.Password)
        # file selectors
        self.excel_edit = QtWidgets.QLineEdit()
        self.driver_edit = QtWidgets.QLineEdit()

        btn_select_excel = QtWidgets.QPushButton("选择 Excel")
        btn_select_driver = QtWidgets.QPushButton("选择 chromedriver")

        btn_select_excel.clicked.connect(self.select_excel)
        btn_select_driver.clicked.connect(self.select_driver)

        form.addRow("网站 URL：", self.site_edit)
        form.addRow("用户名：", self.user_edit)
        form.addRow("密码：", self.pwd_edit)

        h_ex = QtWidgets.QHBoxLayout()
        h_ex.addWidget(self.excel_edit)
        h_ex.addWidget(btn_select_excel)
        form.addRow("Excel 表格：", h_ex)

        h_drv = QtWidgets.QHBoxLayout()
        h_drv.addWidget(self.driver_edit)
        h_drv.addWidget(btn_select_driver)
        form.addRow("ChromeDriver：", h_drv)

        layout.addLayout(form)

        # 操作按钮
        btn_layout = QtWidgets.QHBoxLayout()
        self.btn_save = QtWidgets.QPushButton("保存配置")
        self.btn_test_login = QtWidgets.QPushButton("测试登录")
        self.btn_run = QtWidgets.QPushButton("开始运行（提交）")
        self.btn_stop = QtWidgets.QPushButton("停止")
        self.btn_stop.setEnabled(False)

        self.btn_save.clicked.connect(self.save_config)
        self.btn_test_login.clicked.connect(self.do_test_login)
        self.btn_run.clicked.connect(self.do_run)
        self.btn_stop.clicked.connect(self.do_stop)

        btn_layout.addWidget(self.btn_save)
        btn_layout.addWidget(self.btn_test_login)
        btn_layout.addWidget(self.btn_run)
        btn_layout.addWidget(self.btn_stop)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        # 日志输出
        self.log_browser = QtWidgets.QTextEdit()
        self.log_browser.setReadOnly(True)
        layout.addWidget(QtWidgets.QLabel("运行日志："))
        layout.addWidget(self.log_browser, 1)

        # load config button
        bottom_h = QtWidgets.QHBoxLayout()
        self.btn_load = QtWidgets.QPushButton("加载配置")
        self.btn_clear = QtWidgets.QPushButton("清空已保存配置")
        self.btn_load.clicked.connect(self.load_config_and_apply)
        self.btn_clear.clicked.connect(self.clear_config)
        bottom_h.addWidget(self.btn_load)
        bottom_h.addWidget(self.btn_clear)
        bottom_h.addStretch()
        layout.addLayout(bottom_h)

    def select_excel(self):
        path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "选择 Excel 文件", str(Path.home()), "Excel Files (*.xlsx *.xls)")
        if path:
            self.excel_edit.setText(path)

    def select_driver(self):
        path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "选择 chromedriver 可执行文件", str(Path.home()), "Executables (*.exe);;All Files (*)")
        if path:
            self.driver_edit.setText(path)

    def load_config(self):
        if CONFIG_FILE.exists():
            try:
                raw = json.loads(CONFIG_FILE.read_text(encoding='utf-8'))
                self.config.update(raw)
            except Exception:
                pass

    def _apply_config_to_ui(self):
        self.site_edit.setText(self.config.get("site_url", ""))
        self.user_edit.setText(self.config.get("username", ""))
        self.pwd_edit.setText(self.config.get("password", ""))
        self.excel_edit.setText(self.config.get("excel_path", ""))
        self.driver_edit.setText(self.config.get("driver_path", ""))

    def load_config_and_apply(self):
        self.load_config()
        self._apply_config_to_ui()
        self.log("配置已加载")

    def save_config(self):
        self.config["site_url"] = self.site_edit.text().strip()
        self.config["username"] = self.user_edit.text().strip()
        self.config["password"] = self.pwd_edit.text()
        self.config["excel_path"] = self.excel_edit.text().strip()
        self.config["driver_path"] = self.driver_edit.text().strip()

        try:
            CONFIG_FILE.write_text(json.dumps(self.config, ensure_ascii=False, indent=2), encoding='utf-8')
            self.log(f"配置已保存到 {CONFIG_FILE}")
            QtWidgets.QMessageBox.information(self, "保存成功", "配置已保存")
        except Exception as e:
            QtWidgets.QMessageBox.critical(self, "保存失败", str(e))

    def clear_config(self):
        if CONFIG_FILE.exists():
            CONFIG_FILE.unlink()
        self.config = {
            "site_url": "",
            "username": "",
            "password": "",
            "excel_path": "",
            "driver_path": "",
        }
        self._apply_config_to_ui()
        self.log("配置已清空")

    def log(self, text):
        self.log_browser.append(f"[{QtCore.QDateTime.currentDateTime().toString()}] {text}")

    def do_test_login(self):
        # 只做登录测试（不提交）
        cfg = {
            "site_url": self.site_edit.text().strip(),
            "username": self.user_edit.text().strip(),
            "password": self.pwd_edit.text(),
            "excel_path": self.excel_edit.text().strip(),
            "driver_path": self.driver_edit.text().strip(),
        }
        # quick validation
        if not cfg["driver_path"] or not cfg["site_url"]:
            QtWidgets.QMessageBox.warning(self, "参数缺失", "请先填写 site_url 和 chromedriver 路径")
            return

        self.log("开始测试登录（打开浏览器）...")
        self.btn_test_login.setEnabled(False)
        self.test_thread = QtCore.QThread()
        worker = TestLoginWorker(cfg)
        worker.moveToThread(self.test_thread)
        worker.log_signal.connect(self.log)
        worker.finished_signal.connect(self.on_test_login_finished)
        self.test_thread.started.connect(worker.run)
        self.test_thread.start()

    def on_test_login_finished(self, ok, msg):
        self.log(f"测试登录结束：{msg}")
        QtWidgets.QMessageBox.information(self, "测试登录", msg)
        self.btn_test_login.setEnabled(True)
        # stop thread
        try:
            self.test_thread.quit()
            self.test_thread.wait(2000)
        except Exception:
            pass

    def do_run(self):
        # gather config and save
        self.config["site_url"] = self.site_edit.text().strip()
        self.config["username"] = self.user_edit.text().strip()
        self.config["password"] = self.pwd_edit.text()
        self.config["excel_path"] = self.excel_edit.text().strip()
        self.config["driver_path"] = self.driver_edit.text().strip()
        # validate minimal params
        if not all([self.config["excel_path"], self.config["driver_path"], self.config["site_url"]]):
            QtWidgets.QMessageBox.warning(self, "参数缺失", "请确保已选择 Excel、chromedriver，并填写网站 URL")
            return

        self.save_config()
        self.log("启动后台任务...")
        self.btn_run.setEnabled(False)
        self.btn_stop.setEnabled(True)

        self.worker = WorkerThread(self.config)
        self.worker.log_signal.connect(self.log)
        self.worker.finished_signal.connect(self.on_worker_finished)
        self.worker.start()

    def do_stop(self):
        if self.worker and self.worker.isRunning():
            # 没有可靠的安全中止 selenium 操作的方式，这里尝试请求线程终止
            self.worker.terminate()
            self.log("已请求停止（terminate）线程，浏览器可能未能正常关闭。")
            self.btn_stop.setEnabled(False)
            self.btn_run.setEnabled(True)

    def on_worker_finished(self, success, msg):
        self.log(f"后台任务结束：{msg}")
        QtWidgets.QMessageBox.information(self, "任务结束", msg)
        self.btn_run.setEnabled(True)
        self.btn_stop.setEnabled(False)


class TestLoginWorker(QtCore.QObject):
    log_signal = QtCore.pyqtSignal(str)
    finished_signal = QtCore.pyqtSignal(bool, str)

    def __init__(self, cfg):
        super().__init__()
        self.cfg = cfg

    def run(self):
        try:
            self.log_signal.emit("启动浏览器...")
            driver = setup_selenium(self.cfg["driver_path"])
            self.log_signal.emit("打开登录页并尝试登录...")
            ok = navigate_and_login(driver, self.cfg["site_url"], self.cfg["username"], self.cfg["password"])
            if ok:
                self.finished_signal.emit(True, "登录成功")
            else:
                self.finished_signal.emit(False, "登录可能失败，需要手动输入验证码")
            driver.quit()
        except Exception as e:
            self.finished_signal.emit(False, f"测试登录抛出异常: {e}")

def main():
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
